/* -*-C-*-
*******************************************************************************
*
* File:         MailBox.m
* RCS:          $Header: /usr/local/lib/cvs/EnhanceMail/MailBox.m,v 1.1.1.16 1996/04/07 00:20:20 cedman Exp $
* Description:  
* Author:       Carl Edman
* Created:      Fri Oct 13 11:48:05 1995
* Modified:     Tue Apr  2 20:57:18 1996 (Carl Edman) cedman@capitalist.princeton.edu
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
* (C) Copyright 1995, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/

#import "EnhanceMail.h"
#import "Preferences.h"
#import "MailBox.h"
#import "MailIndex.h"
#import <libc.h>
#import <indexing/indexing.h>

#define MSG_OPEN_MAILBOX NXLoadLocalizedStringFromTableInBundle("Alerts", nil, "Open Mailbox", NULL)
#define MSG_REBUILD_INDEX NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Rebuilding full-text index for %s.  Please wait...", NULL, Message for full text index progressor)

static HashTable *StoreNameHash=nil;
static HashTable *ManagerHash=nil;

struct msgitem
   {
   int number;
   int date;
   struct mflagstruct mflag;
   int totsize;
   int int1;
   int int2;
   };

@implementation EnhanceMailBox
+ finishLoading:(struct mach_header *)header
   {
   [self poseAs:[self superclass]];
   StoreNameHash=[[HashTable alloc] initKeyDesc:"@" valueDesc:"*"];
   ManagerHash=[[HashTable alloc] initKeyDesc:"@" valueDesc:"@"];
   return self;
   }

+ startUnloading
   {
   StoreNameHash=[StoreNameHash free];
   ManagerHash=[ManagerHash free];
   return self;
   }

- initMailBox:(char *)name
   {
   char *storeName=0;
   id manager=nil;
   id ret=[super initMailBox:name];
   
   if (!dirname) return ret;
   storeName=strcpy(malloc(strlen(dirname)+20),dirname);
   strcat(storeName,"/content.store");
   [StoreNameHash insertKey:self value:storeName];

   manager=[[IXRecordManager alloc] initFromName:"content" inFile:storeName forWriting:YES];
   [ManagerHash insertKey:self value:manager];

   [self updateStore];
   return ret;
   }

- free
   {
   char *storeName=[StoreNameHash valueForKey:self];
   id manager=[ManagerHash valueForKey:self];

   [StoreNameHash removeKey:self];
   if (storeName) free(storeName);
   
   [ManagerHash removeKey:self];
   if (manager)
      {
      id store=[manager store];
      [store startTransaction];
      [store compact];
      [store commitTransaction];
      manager=[manager free];
      }
   
   return [super free];
   }

- createStore
   {
   char *storeName=[StoreNameHash valueForKey:self];
   id manager=[ManagerHash valueForKey:self];
   id parser=[[IXAttributeParser alloc] init];

   if (!storeName) return nil;
   if (manager==nil)
      {
      manager=[[IXRecordManager alloc] initWithName:"content" inFile:storeName];
      [ManagerHash insertKey:self value:manager];
      
      [[manager store] startTransaction];
      [manager addAttributeNamed:"msgId" forSelector:@selector(msgId)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"msgId"];
      [manager addAttributeNamed:"Content" forSelector:@selector(messageContent)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Content"];
      [manager setParser:parser forAttributeNamed:"Content"];
#if 0
      [manager addAttributeNamed:"Subject" forSelector:@selector(messageSubject)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Subject"];
      [manager addAttributeNamed:"From" forSelector:@selector(messageFrom)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"From"];
      [manager addAttributeNamed:"To" forSelector:@selector(messageTo)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"To"];
      [manager addAttributeNamed:"Cc" forSelector:@selector(messageCc)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Cc"];
      [manager addAttributeNamed:"Date" forSelector:@selector(messageDate)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Date"];
      [manager addAttributeNamed:"Message-Id" forSelector:@selector(messageId)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Message-Id"];
      [manager addAttributeNamed:"Next-Reference" forSelector:@selector(messageNextReference)];
      [manager setTargetClass:[MailIndex class] forAttributeNamed:"Next-Reference"];
#endif
      [[manager store] commitTransaction];
      }
   return [self updateStore];   
   }

- updateStore
   {
   id manager=[ManagerHash valueForKey:self];
   struct mboxstatus stat;
   int count;
   Progressor *progress;
   MailIndex *record;
   char buf[MAXPATHLEN+1];

   if (manager==nil) return nil;
   [self getMailboxStatus:&stat];
   count=[manager count]-[manager attributeCount];
   if (stat.msgno<=count) return self;
   [[manager store] startTransaction];
   
   sprintf(buf,MSG_REBUILD_INDEX,dirname);
   progress=[Progressor newWithTitle:MSG_OPEN_MAILBOX message:buf];
   [progress setMinValue:count];
   [progress setMaxValue:stat.msgno];
   [progress setProgress:count];
   [progress setShowProgress:YES];
   [progress beginModalSession];
   
   [MailIndex setMailBox:self];
   for(;(count<stat.msgno) && ![progress cancelled];count++)
      {
      record=[[MailIndex alloc] initMsgId:count];
      [manager addRecord:record];
      record=[record free];
      [progress setProgress:count];
      }
   [MailIndex setMailBox:nil];
   
   [progress endModalSession];
   [[manager store] commitTransaction];

   return (count>=stat.msgno) ? self : nil;
   }

- deleteStore
   {
   char *storeName=[StoreNameHash valueForKey:self];
   id manager=[ManagerHash valueForKey:self];
      
   if (!storeName)
      return nil;

   if (manager)
      [ManagerHash insertKey:self value:(manager=[manager free])];

   if (unlink(storeName)==-1)
      return nil;

   return self;
   }

- (BOOL)hasStore
   {
   id manager=[ManagerHash valueForKey:self];
      
   return (manager==nil) ? NO : YES;
   }

- (int)storeSize
   {
   char *storeName=[StoreNameHash valueForKey:self];
   id manager=[ManagerHash valueForKey:self];
   struct stat buf;
   
   if ((manager==nil)||(storeName==0)||(stat(storeName,&buf)==-1)) return -1;
   
   return buf.st_size;
   }

- (void)maybeUpdateToc
   {
   [super maybeUpdateToc];
   [self updateStore];
   }

- repairTocFile:(int)start
   {
   id ret=[super repairTocFile:start];
   [self updateStore];
   return ret;
   }

- query:(const char *)expr
   {
   id manager,parser,query,list;

   manager=[ManagerHash valueForKey:self];
   if (manager==nil) return nil;
   parser=[manager parserForAttributeNamed:"Content"];
   if (parser==nil) return nil;
   query=[[IXAttributeQuery alloc] initQueryString:expr andAttributeParser:parser];
   if (query==nil) return nil;
   list=[query evaluateFor:manager];
   [query free];
   return list;
   }
@end
